#include "main.h"

#define APP_FLASH_START_CHECK_CODE                 ((uint32_t)0xA5A5A5A5)
#define APP_FLASH_END_CHECK_COD                    ((uint32_t)0x5A5A5A5A)
#define CODE_FLASH_START_ADDR                      ((uint32_t)(Load$$ER_IROM1$$Base))
#define CODE_FLASH_END_ADDR                        ((uint32_t)(Load$$RW_IRAM1$$Limit - 0x04))

#define EXE_ENTER_UPDATE_MODE                      ((uint8_t)0x02)

uint16_t uiSysFlags = 0;

typedef void (*IAPFuc)(void);
IAPFuc BootloaderReset_Handler;

extern uint8_t Load$$ER_IROM1$$Base[];
extern uint8_t Load$$RW_IRAM1$$Limit[];

extern STRxDataFrame stRxData;

typedef struct{
	uint32_t ulAppStartCheckCode;
	uint32_t ulStartAddr;
	uint32_t ulEndAddr;
	uint32_t reserve[61];
}STFlashComInfoType;

const STFlashComInfoType stAppFlashInfo __attribute__((used, section(".code_info"))) = {
	APP_FLASH_START_CHECK_CODE,
	CODE_FLASH_START_ADDR,
	CODE_FLASH_END_ADDR,
	{0}
};

static volatile uint32_t ulAppFlashEndCheckCode __attribute__((used, section(".CodeEndFlag"))) = APP_FLASH_END_CHECK_COD;

void vAppUsartHandler(void);
void vIAPSwitchToBootloader(void);
void vSendData(uint8_t *pdata, uint16_t len);
void vResponseHost(uint8_t cmd, uint8_t result);

int main(void)
{
	SCB->VTOR = (0x00000000 | 0x4100);
	
    /* Initialize FL Driver Library */
    /* SHOULD BE KEPT!!! */
    FL_Init();

    /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
    /* SHOULD BE KEPT!!! */
    MF_Clock_Init();

    /* Initialize all configured peripherals */
    /* SHOULD BE KEPT!!! */
    MF_Config_Init();

    while(1)
    {
		vAppUsartHandler();
		//FL_DelayMs(500);
    }
}

void vAppUsartHandler(void)
{
	if(GET_UART_RX_FINISH())
	{
		switch(stRxData.frame.stCmdFrame.ucCmd)
		{
			case EXE_ENTER_UPDATE_MODE:
				vIAPSwitchToBootloader();
				break;
			
			default:
				break;
		}
		
		memset((uint8_t *)&stRxData, 0x00, sizeof(stRxData));
		CLR_UART_RX_FINISH();
	}
}

__asm void MSR_MSP(uint32_t addr) 
{
    MSR MSP, r0 //set Main Stack value
    BX r14
}

void vIAPSwitchToBootloader(void)
{
	uint32_t bootloaderAddr = 0x00000000;
	uint8_t i = 0;
	
	if((*((uint32_t *)bootloaderAddr) & 0x2FFE0000) == 0x20000000)
	{
		BootloaderReset_Handler = (IAPFuc) *((uint32_t *)(bootloaderAddr + 4)); // Reset_Handler
		
		__set_PRIMASK(1);
		
		SysTick->CTRL = 0;
		SysTick->LOAD = 0;
		SysTick->VAL = 0;
		
		for (i = 0; i < 8; i++)
        {
            NVIC->ICER[i]=0xFFFFFFFF;
            NVIC->ICPR[i]=0xFFFFFFFF;
        }
		
		__set_PRIMASK(0);
		
		MSR_MSP(*(uint32_t*)bootloaderAddr);
		
		vResponseHost(0x02, 0xFE);
		
		BootloaderReset_Handler();
	}
}

void vResponseHost(uint8_t cmd, uint8_t result)
{
	uint8_t ucReply[5] = {0x00};
	
	ucReply[0] = 0xA5;
	ucReply[1] = cmd;
	ucReply[2] = result;
	ucReply[3] = 0x0D;
	ucReply[4] = 0x0A;
	vSendData(ucReply, 5);
}

void vSendData(uint8_t *pdata, uint16_t len)
{
	uint16_t i = 0;
	uint16_t timeout = 0xffff;
	
	for(i = 0; i < len; i++)
	{
		FL_UART_WriteTXBuff(UART0, (uint8_t)pdata[i]);
		while((FL_UART_IsActiveFlag_TXShiftBuffEmpty(UART0) != 0x01UL) && (timeout--));
	}
}

int fputc(int ch, FILE *f)
{
	FL_UART_WriteTXBuff(UART0, (uint8_t)ch);
	while(FL_UART_IsActiveFlag_TXShiftBuffEmpty(UART0) != 0x01UL);		
	
	return (ch);
}

int fgetc(FILE *f)
{
	while(FL_UART_IsActiveFlag_RXBuffFull(UART0) == 0x01UL);

	return (int)FL_UART_ReadRXBuff(UART0);
}
